<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>闭包</title>
  </head>
  <body>
    <div>
      <button>按钮1</button>
      <button>按钮2</button>
      <button>按钮3</button>
    </div>
    <script>
      //    闭包定义： 函数嵌套函数，内部函数可以访问外部函数的变量，变量的作用域只能在函数内部
      //   let num = 20;
      /** 1.计数器的闭包
       * function outer() {
        var num = 10;
        // var num1 = 0
        return function() {
        //  num1 = ++num; // num++ 表示先赋值再自增，++num 表示先自增再赋值
          console.log(num)
        }
      }
      const p = outer();
      p()
      **/

      /* 2. 私有变量
      function createPerson(name) {
        let age = 0;
        return {
            getName: function () {
                return name
            },
            incrementAge:function () {
               age++;
            }
        }
      }

      const person = createPerson('zhangsan');
      console.log(person.incrementAge()) */

      /*  3.解决循环中的闭包问题
      for(var i= 0;i<5;i++) {
        //  会在循环结束后才执行
        setTimeout(function () {
          console.log(i) // 5个5
        },200)
      }

      // 使用let声明i块级作用域   隔离作用域
      for(let i=0;i<5;i++) {
        setTimeout(function () {
          console.log(i) // 0 1 2 3 4
        },200)
      }

      for(var i=0;i<5;i++) {
        // 立即执行函数  立即执行函数的作用域是独立的
        (function(i) {
          setTimeout(function () {
            console.log(i) // 0 1 2 3 4
          },200)
        })(i)
      } */

      /* 模块化
       const myModule =  (function(){
        let age = 10;
        return {
          getAge:function () {
            return age
          },
          getName: function(name) {
            return name
          },
          add(a,b) {
            return a+b
          }
        }
      })()

      console.log(myModule.getAge())
      console.log(myModule.getName("zs"))
      console.log(myModule.add(1,2)) */

      /*  事件处理的闭包
      
      function setButtonClick() {
        const buttons = document.querySelectorAll("button");
        for (let i = 0; i < buttons.length; i++) {
          buttons[i].onclick = function () {
            console.log("按钮" + i + "被点击了");
          };
        }
      }

      setButtonClick(); */
      /* 
      闭包的问题：
      1.闭包会保持对外部变量的引用，可能导致内存无法被回收，造成内存泄漏。
      2.闭包可能会导致性能问题，闭包的访问速度比普通变量稍慢，因为需要访问外部作用域。
      3.闭包可能会导致代码可读性下降，因为闭包的作用域是不明确的。 */

      function createHeavyObject() {
        const largeArray = new Array(1000000).fill("data");

        return function () {
          console.log(largeArray.length); // 保持对largeArray的引用
        };
      }
      const heavyObject = createHeavyObject();
      heavyObject();
      heavyObject = null; // 释放对largeArray的引用 在不需要时手动解除引用。允许垃圾回收
    </script>
  </body>
</html>
